package com.haoran.dwz.siteminder.aspect;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.text.MessageFormat;
import java.util.Date;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.haoran.dwz.common.util.AddressUtil;
import com.haoran.dwz.domain.entities.ApiLog;
import com.haoran.dwz.repository.ApiLogRepository;
import com.haoran.dwz.util.IPUtil;
import com.haoran.dwz.util.MailUtil;

@Component
@Aspect
public class ApiControllerAspect {

	@Pointcut("execution(public * com.haoran.dwz.modules.dwz.*Controller.*(..))")
	public void api() {
	}

	@Around("api()")
	public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
		ApiLog entity = new ApiLog();
		long currentTimeMillis = System.currentTimeMillis();
		Date requestTime = new Date(currentTimeMillis);
		entity.setRequestTime(requestTime);
		Object proceed = null;
		try {
			proceed = joinPoint.proceed();
			entity.setSuccess(true);
		} catch (Exception e) {
			entity.setSuccess(false);
			entity.setException(e);
			throw e;
		}finally {
			ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
			HttpServletRequest request = attributes.getRequest();
			StringBuffer requestURL = request.getRequestURL();
			// 类方法
			String method = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
			// 参数
			Object[] args = joinPoint.getArgs();
			entity.setRequestUrl(requestURL.toString());
			entity.setRequestIP(IPUtil.getIpAddress(request));
			entity.setServerIP(AddressUtil.getHostAddress());
			entity.setResponseTime(requestTime);
			if(proceed != null) {
				String response = proceed.toString();
				entity.setResponse(response);
				long takeTime = System.currentTimeMillis() - currentTimeMillis;
				entity.setTakeTime(takeTime);
			}else {
				entity.setSuccess(false);
			}
			entity.setMethod(method);
			if(args != null) {
				// 从切点上获取目标方法
				MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
				logger.debug("methodSignature : " + methodSignature);
				Method method1 = methodSignature.getMethod();
				Parameter[] parameters = method1.getParameters();
				for (int i = 0; i < parameters.length; i++) {
					if(parameters[i].isAnnotationPresent(RequestBody.class)) {
						 String mapJakcson = mapper.writeValueAsString(args[i]);
						 entity.setParams(mapJakcson);
					}
				}
			}
			queue.put(entity);
		}
		return proceed;
	}

	@Autowired
	private ApiLogRepository apiLogRepository;
	@Autowired
	private  MailUtil mailUtil;
	private ObjectMapper mapper = new ObjectMapper();
	private String serverIp;
	private final BlockingQueue<ApiLog> queue = new ArrayBlockingQueue<ApiLog>(1);
	private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());

	@PostConstruct // 定义在构造方法完毕后，执行这个初始化方法
	public void init() {
		serverIp = AddressUtil.getHostAddress();
		logger.info("IP:{} startup saving apilog thread.",serverIp);
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					ApiLog log = null;
					try {
						log = queue.take();
						apiLogRepository.save(log);
						if(!log.isSuccess()) {
							String trakeError = "";
							if(log.getException() != null) {
								trakeError = printStackTraceToString(log.getException());
							}
							String mailSubject = "《接口故障监控报警》(WEB服务接口平台USM)";
							String mailBody = MessageFormat.format("接口调用失败, 接口方法名称:{0}\n    入参: {1}.\n    服务器地址:{2} \n    请求时间:{3}\n    请求地址:{4} \n  请求出参:{5} \n  异常堆栈:\n{6}", log!=null?log.getMethod():"null", log.getParams(),log.getServerIP(),log.getRequestTime(),log.getRequestUrl(),log.getResponse(),trakeError);
							mailUtil.sendMail(null, mailSubject, mailBody, false, null);
						}
						logger.info("save success !");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
	
	public static String printStackTraceToString(Throwable t) {
	    StringWriter sw = new StringWriter();
	    t.printStackTrace(new PrintWriter(sw, true));
	    return sw.getBuffer().toString();
	}
}
